package cc.flyflow.core.listeners.impl;

import cc.flyflow.common.dto.process.ProcessInstanceRecordParamDto;
import cc.flyflow.common.utils.JsonUtil;
import cc.flyflow.core.listeners.EventListenerStrategy;
import cc.flyflow.core.utils.BizHttpUtil;
import cc.flyflow.core.utils.ExecutionUtil;
import cc.flyflow.core.utils.FlowableUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.event.impl.FlowableProcessStartedEventImpl;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Map;

import static cc.flyflow.common.constants.ProcessInstanceConstant.VariableKey.*;

/**
 * 流程开始了
 * <p>
 * 进程启动事件监听器
 *
 * @author Huijun Zhao;Jyl
 * @date 2023-10-10 10:12
 */
@Slf4j
@Component
public class ProcessStartedEventListener implements EventListenerStrategy, InitializingBean
{

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 处理数据
     *
     * @param event 流程事件
     */
    @Override
    public void handle(FlowableEvent event)
    {
        //流程开始了
        FlowableProcessStartedEventImpl flowableProcessStartedEvent = (FlowableProcessStartedEventImpl) event;
        ExecutionEntityImpl entity = (ExecutionEntityImpl) flowableProcessStartedEvent.getEntity();
        DelegateExecution execution = flowableProcessStartedEvent.getExecution();

        String flowId = entity.getProcessDefinitionKey();
        String nestedProcessInstanceId = flowableProcessStartedEvent.getNestedProcessInstanceId(); //上级实例id 主要是涉及到子流程的

        {
            //设置唯一id
            String s = IdUtil.fastSimpleUUID();
            String key = StrUtil.format(REDIS_KEY_OF_FLOW_UNIQUE_ID, entity.getProcessInstanceId());
            String value = StrUtil.format("{}||||{}", START_NODE, s);
            redisTemplate.opsForZSet().add(key, value, System.currentTimeMillis());
        }

        String processInstanceId = flowableProcessStartedEvent.getProcessInstanceId();
        String startUserId = FlowableUtils.getStartUserId(execution);
        String tenantId = entity.getTenantId();
        String dateTime = DateUtil.format(new Date(), "yyyyMMddHHmmss");
        String processInstanceBizCode = StrUtil.format("BIZ{}{}", dateTime, RandomUtil.randomStringUpper(6)); //流程编号

        Map<String, Object> variables = execution.getVariables();

        log.info("发起人id：{}", startUserId);

        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
        runtimeService.setVariable(processInstanceId, PROCESS_INSTANCE_CODE, processInstanceBizCode);

        ProcessInstanceRecordParamDto recordParamDto = new ProcessInstanceRecordParamDto();
        recordParamDto.setUserId(startUserId);
        recordParamDto.setMainDeptId(MapUtil.getStr(variables, START_USER_MAIN_DEPTID_KEY));
        recordParamDto.setParentProcessInstanceId(nestedProcessInstanceId);
        recordParamDto.setFlowId(flowId);

        recordParamDto.setTenantId(tenantId);
        recordParamDto.setProcessInstanceId(processInstanceId);
        recordParamDto.setProcessInstanceBizKey(entity.getProcessInstanceBusinessKey());
        recordParamDto.setProcessInstanceBizCode(processInstanceBizCode);
        recordParamDto.setFormData(JsonUtil.toJSONString(variables));

        //判断是子流程启动
        if (StrUtil.isNotBlank(nestedProcessInstanceId))
        {
            String superExecutionId = execution.getParent().getSuperExecutionId();
            String parentExecutionId = ExecutionUtil.getParentExecutionId(superExecutionId);
            recordParamDto.setParentProcessNodeExecutionId(parentExecutionId);
        }
        BizHttpUtil.processStartEvent(recordParamDto);
    }

    @Override
    public void afterPropertiesSet() throws Exception
    {
        afterPropertiesSet(FlowableEngineEventType.PROCESS_STARTED.toString());
    }
}
